﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using Microsoft.Xna.Framework;
using System.Windows.Media;
using System.Threading;
using System.Windows.Threading;

namespace StaticView
{
    // Display object
    //      Contain Display thread
    //      Handle the transformation
    class Display
    {
        // Constant
        const float ZDEVTHRES = (float)(Math.PI * 10 / 180); // Z deviation thresold
        const int FPS = 60; // Frame per sec

        StaticField field;
        volatile bool stop = false;
        Viewer viewer;

        bool transformOK = false;

        public Display(StaticField field, Viewer viewer)
        {
            this.field = field;
            this.viewer = viewer;
        }

        public void Run()
        {
            while (!stop)
            {
                if (Transform())
                {
                    // If Transform OK, render it
                    if (field.Document.RequestChange())
                        viewer.setCanvas(field.Document.GetImage());
                    // If the previous transformation is not OK, show the view again
                    if (!transformOK)
                        viewer.Visible(true);
                    transformOK = true;
                }
                else
                {
                    if (transformOK)
                        viewer.Visible(false);
                    transformOK = false;
                }

                // Sleep the thread
                Thread.Sleep(1000 / FPS);
            }
        }

        bool Transform()
        {
            // Get the current direction
            Vector3 localz = Position.Normal;
            Vector3 localx = Position.LocalX;
            // Get the field direction
            Vector3 fieldz = field.Normal;
            Vector3 fieldx = field.LocalX;
            // Calculate the Z deviation

            float prod = Vector3.Dot(localz, fieldz) / (localx.Length() * localz.Length());
            if (prod > 1) prod = 1;
            if (prod < -1) prod = -1;
            float zDev = (float)Math.Acos(prod);

            if (zDev > ZDEVTHRES) // If the Z deviation larger than the thresold
                return false; // Not render the image
            else
            {
                Vector3 rotAxis = Vector3.Cross(localz, fieldz); // Rotation axis which rotates the LocalZ to FieldZ
                Quaternion q = Quaternion.CreateFromAxisAngle(rotAxis, zDev); // The quaternion represents the rotation
                Vector3 proLocalX = Vector3.Transform(localx, q); // Project the LocalX to the Field plane

                // Calculate the X deviation
                prod = Vector3.Dot(proLocalX, fieldx) / (proLocalX.Length() * fieldx.Length());
                if (prod > 1) prod = 1;
                if (prod < -1) prod = -1;
                float xAngle = (float)Math.Acos(prod);
                Vector3 xDir = Vector3.Cross(proLocalX, fieldx); // The direction of X (from LocalX to FieldX)
                if (Vector3.Dot(xDir, fieldz) < 0) // Negative angle
                    xAngle = -xAngle;

                // Transform the canvas
                viewer.Rotate(xAngle * 180 / (float)Math.PI);

                return true;
            }

        }
    }
}
